#include <argz.h>
#include <sound.h>
//
// Created by ChenJi on 2020/11/28.
//

#include "finger_sener.h"
#include "usart_extern.h"
#include "string_library.h"
/* languages */





/* shake hand pocket */
uint8_t HAND_SHAKE_POCKET[] = {0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x03, 0x40, 0x00, 0x44};
/* get valid temples amount */
uint8_t GET_VALID_TEMP_NUMBER[] = {0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x03, 0x1D, 0x00, 0x21};

/* led pockets */
uint8_t BLUE_LED[] = {0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x07, 0x35, 0x02, 0x00, 0x02, 0x00, 0x00, 0x41};
uint8_t Close_LED[] = {0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x07, 0x35, 0x04, 0x00, 0x02, 0x00, 0x00, 0x43};
uint8_t RED_LED[] = {0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x07, 0x35, 0x02, 0x00, 0x01, 0x00, 0x00, 0x40};
uint8_t PURPLE_LED[] = {0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x07, 0x35, 0x02, 0x00, 0x03, 0x00, 0x00, 0x42};
/* verify pockets */
uint8_t GET_IMAGE[] = {0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x03, 0x01, 0x00, 0x05};
uint8_t GET_CHAR[] = {0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x04, 0x02, 0x01, 0x00, 0x08};
uint8_t SEARCH[] = {0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x08, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x0E};
/* import sensor */

uint8_t GENERATE_CHAR_01[] = {0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x04, 0x02, 0x01, 0x00, 0x08};
uint8_t GENERATE_CHAR_02[] = {0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x04, 0x02, 0x02, 0x00, 0x09};
uint8_t GENERATE_CHAR_03[] = {0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x04, 0x02, 0x03, 0x00, 0x0A};
uint8_t GENERATE_CHAR_04[] = {0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x04, 0x02, 0x04, 0x00, 0x0B};
uint8_t GENERATE_CHAR_05[] = {0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x04, 0x02, 0x05, 0x00, 0x0C};
uint8_t GENERATE_CHAR_06[] = {0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x04, 0x02, 0x06, 0x00, 0x0D};

/* pocket buffer */
uint8_t buffer[128];


extern UART_HandleTypeDef huart2;
/* the index of buffer */
int nowIndex = 0;
/* the length of the pocket. fetch it from the 9th data */
uint8_t pocket_length;
/* wait for data */
uint8_t isReading = 0;


/* init configs */
uint8_t finger_sensor_is_initing = 0;
uint8_t is_Waiting_TMP_Number = 0;
uint8_t templeNumber;

/* state from pocket */
uint8_t finger_sensor_state = 254;

/* the amount of verify failed */
uint8_t fail_amount = 0;
const uint8_t max_fail_amount;
/* verify state code */
uint8_t verify_state = 254;//254 notstate 0-waiting for finger. 1-fetch done 2-character done

/* is waiting for led settled reply */
uint8_t isWaitingLED = 0;

/* register finger */
uint8_t in_register_finger_mode = 0;
uint8_t waiting_for_finger_read = 0;
uint8_t now_input_amount = 0;
uint8_t save_location = 0;
uint8_t register_wait_for_gen_char = 0;
uint8_t register_wait_for_image = 1;

void registerFinger() {
    in_register_finger_mode = 1;
    verify_state = 254;
    register_wait_for_image = 1;
    debug_sync("[FingerSensor]Start register finger");

}

uint8_t isIniting() {
    return finger_sensor_is_initing;
}

/**
 * set the LED to BLUE
 */
void setBlueLED() {
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);
    isWaitingLED = 1;
    sendData_DMA(BLUE_LED, &huart2, sizeof(BLUE_LED));
}

/**
 * set the LED to RED
 */
void setRedLED() {
    isWaitingLED = 1;
    sendData_DMA(RED_LED, &huart2, sizeof(RED_LED));
}

/**
 * close LED
 */
void closeLED() {
    isWaitingLED = 1;
    sendData_DMA(Close_LED, &huart2, sizeof(Close_LED));
}

/**
 * set the LED to purple
 */
void setPurpleLED() {
    isWaitingLED = 1;
    sendData_DMA(PURPLE_LED, &huart2, sizeof(PURPLE_LED));
}

/**
 * send Shake-Hand pocket
 */
void sendHandShake() {
    sendData_DMA(HAND_SHAKE_POCKET, &huart2, sizeof(HAND_SHAKE_POCKET));
}

/**
 * this is a event on finger touched on the sensor.
 */
void onFingerTouch() {
    if (verify_state == 0) {
        sendData_DMA(GET_IMAGE, &huart2, sizeof(GET_IMAGE));
    }
    /**
     *     if (in_register_finger_mode && register_wait_for_image) {
        sendData_DMA(GET_IMAGE, &huart2, sizeof(GET_IMAGE));
        waiting_for_finger_read = 1;
    }
     */

}

/**
 * this is a event on finger left the sensor.
 */
void onFingerLeave() {
}

/**
 * try to take steps to verify finger when next Finger-touch-event happened.
 */
void verifyFinger() {
    setBlueLED();
    verify_state = 0;
    setFingerSensorData(1);
    RESET_ALL_LED;
}


void onGPIOSwap_1_C(GPIO_PinState state) {
    if (state == GPIO_PIN_SET)
        onFingerLeave();
    else
        onFingerTouch();

}

/**
 * rewrite the function from usart_extern.c
 * this is a event on UART2 receive a byte.
 * @param data data from dma buffer.
 */
void onUART2Receive(uint8_t data) {
    if (data == 0xEF) {
        isReading = 1;
        pocket_length = 0;
        nowIndex = 0;
    }
    if (isReading) {
        buffer[nowIndex] = data;
        if (isReading && nowIndex == 8) {
            if (buffer[0] == 0xEF && buffer[1] == 0x01 && buffer[2] == 0xFF && buffer[3] == 0xFF && buffer[4] == 0xFF &&
                buffer[5] == 0xFF) {
                pocket_length = buffer[nowIndex];
            }
        }
        if (pocket_length != 0 && nowIndex == 8 + pocket_length) {
            finger_sensor_state = buffer[9];
            handlePocket();
            isReading = 0;
            nowIndex = 0;
        }
        nowIndex++;
    }
}

void initFingerSensor() {
    finger_sensor_is_initing = 1;
    sendHandShake();
}

void button1HoldCycleCallback() {
    sendData_DMA(GENERATE_CHAR_01, &huart2, sizeof(GENERATE_CHAR_01));
}

void handlePocket() {
    if (buffer[6] != 0x07)  //only 0x07 meaning reply pocket;
        return;
    if (finger_sensor_is_initing && finger_sensor_state == 0x00) {
        finger_sensor_is_initing = 0;
        is_Waiting_TMP_Number = 1;
        debug("[FingerSensor]Loading\n");
        sendData_DMA(GET_VALID_TEMP_NUMBER, &huart2, sizeof(GET_VALID_TEMP_NUMBER));
        return;
    }
    if (is_Waiting_TMP_Number && finger_sensor_state == 0x00) {
        is_Waiting_TMP_Number = 0;
        templeNumber = buffer[11];
        SEARCH[16] = SEARCH[16] + templeNumber;
        SEARCH[14] = templeNumber;  /**notice**/
        setPurpleLED();
        uint8_t data[4];
        myitoa(templeNumber, data, 10);
        debug_sync("[FingerSensor]Amount: ");
        debug_sync(data);
        debug_sync("\n");
        debug("[FingerSensor]Load Done\n");
        return;
    }
    if (isWaitingLED && finger_sensor_state == 0x00) {
        isWaitingLED = 0;
        return;
    }
    /*
    if (register_wait_for_image) {
        if (finger_sensor_state == 0x00) {
              debug("[FingerSensor]Finger Done\n");
            //setFingerSensorData(5 + now_input_amount);
            register_wait_for_image = 0;
            register_wait_for_gen_char = 1;
            switch (now_input_amount) {
                case 0:
                  //  debug("[FingerSensor]Generate 01\n");
                    sendData_DMA(GENERATE_CHAR_01, &huart2, sizeof(GENERATE_CHAR_01));
                    return;
                case 1:
                //    debug("[FingerSensor]Generate 02\n");
                    sendData_DMA(GENERATE_CHAR_02, &huart2, sizeof(GENERATE_CHAR_02));

                    return;
                case 2:
                  //  debug("[FingerSensor]Generate 03\n");
                    sendData_DMA(GENERATE_CHAR_03, &huart2, sizeof(GENERATE_CHAR_03));

                    return;
                case 3:
                  //  debug("[FingerSensor]Generate 04\n");
                    sendData_DMA(GENERATE_CHAR_04, &huart2, sizeof(GENERATE_CHAR_04));

                    return;
                case 4:
                //    debug("[FingerSensor]Generate 05\n");
                    sendData_DMA(GENERATE_CHAR_05, &huart2, sizeof(GENERATE_CHAR_05));

                    return;
                case 5:
               //     debug("[FingerSensor]Generate 06\n");
                    sendData_DMA(GENERATE_CHAR_06, &huart2, sizeof(GENERATE_CHAR_06));
                    return;
                default:
                    return;
            }
        } else {
            debug("[FingerSensor]Verify Failed,Finger is too dirty to be identified.\n");
            register_wait_for_image = 1;
            register_wait_for_gen_char = 0;
            return;
        }
    }    debug_sync("[FingerSensor]Debug_02\n");
    if (register_wait_for_gen_char) {
        if (finger_sensor_state == 0x00) {
            if (now_input_amount == 5) {
                debug("[FingerSensor]Register for.\n");
            } else {
                debug("[FingerSensor]Generate Done.For next.\n");
                now_input_amount++;
                register_wait_for_image = 1;
            }
        } else {
            debug("[FingerSensor]Verify-Failed,Finger cannot create char.\n");
            register_wait_for_gen_char = 0;
            register_wait_for_image = 1;
        }
    }
    */

    if (verify_state == 0) { //wait for finger
        if (finger_sensor_state == 0x00) {
            verify_state = 1;
            sendData(GET_CHAR, &huart2, sizeof(GET_CHAR));
            LED_R_SET;
            debug("[FingerSensor]Touched,getting char\n");
            return;
        } else {
            LED_R_RESET;
            onVerifyFailed(1);
            return;
        }
    }
    if (verify_state == 1) { //wait for char
        if (finger_sensor_state == 0x00) {
            verify_state = 2;
            LED_G_SET;
            sendData(SEARCH, &huart2, sizeof(SEARCH));
            debug("[FingerSensor]gained char.searching\n");
            return;
        } else {
            LED_G_RESET;
            onVerifyFailed(2);
            return;
        }
    }
    if (verify_state == 2) { //wait for result
        if (finger_sensor_state == 0x00) {
            verify_state = 254;
            uint16_t id = buffer[10] + buffer[11];
            uint16_t score = buffer[12] + buffer[13];
            debug_sync("[FingerSensor]search done,ID:");
            uint8_t data[4];
            myitoa(id, data, 10);
            debug_sync(data);
            debug_sync(" Score: ");
            myitoa(score, data, 10);
            debug_sync(data);
            debug_sync("\n");
            onVerifySuccess(id, score);
            LED_B_SET;
        } else {
            onVerifyFailed(3);
            LED_B_RESET;
            return;
        }
    }
}

__weak void onVerifyFailed(uint8_t code) {
    if (code == 1)
        debug("Verify-Failed,Finger is too dirty to be identified.\n");
    else if (code == 2)
        debug("Verify-Failed,Finger cannot create char.\n");
    else if (code == 3)
        debug("Verify_Failed,Finger cannot be identified.\n");
    verify_state = 0;
    setRedLED();
    fail_amount++;
    playSoundAsync(7);
    setFingerSensorData(2);
}

__weak void onVerifyAmountOverLimit() {

}

__weak void onVerifySuccess(uint16_t number, uint16_t score) {
    setFingerSensorData(3);
    closeLED();
}
